package com.exercise.widgets.chip.wrapper

import android.content.Context
import android.database.Observable
import android.util.AttributeSet
import android.view.ViewGroup
import androidx.core.view.children
import com.google.android.material.R
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.chip.ChipGroup.OnCheckedStateChangeListener
import com.google.android.material.snackbar.Snackbar

class DynamicChipView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet,
    defStyleAttr: Int = R.attr.chipGroupStyle
) : ChipGroup(context, attrs, defStyleAttr), OnCheckedStateChangeListener {
    /**
     * 用于在数据变化时回调更新视图
     */
    private val mDataObserver = DynamicChipViewDataObserver()
    private lateinit var mAdapter: Adapter<*>
    private var mOnCheckedStateChangeListener: OnCheckedStateChangeListener? = null

    init {
        /**
         * 注册监听，选中项有变化时及时通知[Adapter.updateCheckedItems]中进行修改
         */
        setOnCheckedStateChangeListener(this)
    }

    fun setAdapter(adapter: Adapter<*>) {
        setAdapterInternal(adapter)
    }

    private fun setAdapterInternal(adapter: Adapter<*>) {
        // 避免重复监听
        if (::mAdapter.isInitialized && mAdapter.hasObserver(mDataObserver)) {
            mAdapter.unregisterAdapterDataObserver(mDataObserver)
            mAdapter.onDetachedFromChipView(this)
        }
        mAdapter = adapter
        mAdapter.registerAdapterDataObserver(mDataObserver)
        mAdapter.onAttachedToChipView(this)
        mAdapter.notifyDateSetChanged()
    }

    /**
     * 更新视图
     *
     */
    private fun updateView() {
        if (childCount > 0) {
            removeAllViews()
        }
        for (index in 0..<mAdapter.getItemCount()) {
            val childChip = mAdapter.onCreateItemChipView(index, this).apply {
                text = mAdapter.onBindItem(index)
            }
            addView(childChip)
        }
    }

    /**
     * 用于注册选择状态变化监听事件
     *
     * @param listener
     */
    override fun setOnCheckedStateChangeListener(listener: OnCheckedStateChangeListener?) {
        if (listener is DynamicChipView) {
            super.setOnCheckedStateChangeListener(listener)
        } else {
            mOnCheckedStateChangeListener = listener
        }
    }

    /**
     * Checked状态发生变化时回调
     *
     * @param group
     * @param checkedIds
     */
    override fun onCheckedChanged(group: ChipGroup, checkedIds: MutableList<Int>) {
        // 把已选的id转换为下标
        val checkedIndex = checkedIds.map { viewId ->
            children.indexOfFirst { viewId == it.id }
        }
        //通知Adapter更新已选项
        mAdapter.updateCheckedItems(checkedIndex)
        //回调其他监听
        mOnCheckedStateChangeListener?.onCheckedChanged(group, checkedIds)
    }

    /**
     * 真正的观察者，数据发生变化时会回调该对象
     */
    inner class DynamicChipViewDataObserver : AdapterDataObserver() {
        override fun onChanged() {
            updateView()
        }
    }

    /**
     * 观察者容器
     * 用于注册/反注册观察者对象，并通知观察者进行更新操作等.
     */
    class AdapterDataObservable : Observable<AdapterDataObserver>() {
        fun hasObserver(observer: AdapterDataObserver): Boolean {
            return mObservers.contains(observer)
        }

        fun notifyChanged() {
            for (i in mObservers.lastIndex downTo 0) {
                mObservers[i].onChanged()
            }
        }
    }

    /**
     * 观察者基类
     */
    open class AdapterDataObserver {
        /**
         *回调方法，通过回调该方法更新View
         */
        open fun onChanged() {}
    }

    abstract class Adapter<T> {
        private val mObservable = AdapterDataObservable()
        abstract fun onCreateItemChipView(index: Int, parent: ViewGroup): Chip
        abstract fun onBindItem(index: Int): String
        abstract fun getItemCount(): Int

        /**
         * 更新已选列表
         * 通过[DynamicChipView.onCheckedChanged]调用更新
         *
         * @param checkedIndexList 当前已选item的下标列表
         */
        abstract fun updateCheckedItems(checkedIndexList: List<Int>)

        fun registerAdapterDataObserver(observer: AdapterDataObserver) {
            mObservable.registerObserver(observer)
        }

        fun unregisterAdapterDataObserver(observer: AdapterDataObserver) {
            mObservable.unregisterObserver(observer)
        }

        fun hasObserver(observer: AdapterDataObserver): Boolean {
            return mObservable.hasObserver(observer)
        }

        fun notifyDateSetChanged() {
            mObservable.notifyChanged()
        }

        open fun onAttachedToChipView(chipView: DynamicChipView) {

        }

        open fun onDetachedFromChipView(chipView: DynamicChipView) {

        }
    }

}
